package jiang.Algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName DigitConvert
 * @Description: 数字大写转阿拉伯数字格式
 * @Author jiangshitao
 * @Date 2023/1/29
 */
public class DigitConvert {
    /**
     * 之前面试多益网络遇到了阿拉伯数字转汉字的，
     * 今天在公司项目代码里找到了汉字数字转阿拉伯数字的算法
     * 复制过来看看公司大佬是怎么写的，学习一下
     */
    private static final char[] UPPER = {'零','壹','贰','叁','肆','伍','陆','柒','捌','玖'};
    private static final char[] NUIT = {'拾','佰','仟','万','亿'};
    private static final String[] NUIT2 = {"","拾","佰","仟","","万","亿"};
    private static final char[] DIGIT = {'0','1','2','3','4','5','6','7','8','9'};
    private static final Map<Character, Character> mapU = new HashMap<>();
    private static final Map<Character, Character> mapD = new HashMap<>();
    private static final List<Character> listN = new ArrayList<>();

    static {
        for(int i = 0; i < DIGIT.length; i++){
            mapU.put(DIGIT[i], UPPER[i]);
            mapD.put(UPPER[i], DIGIT[i]);
        }
        for (char c : NUIT) {
            listN.add(c);
        }
    }

    /**
     * 大写汉字转阿拉伯数字
     * @param upper 待转换大写数字汉字
     * @return 转换结果
     */
    public static String convertToDigit(String upper) {
        // 倍数
        long digit = 1L;
        // 最终结果
        long result = 0L;
        // 前一次转换后的数
        long pre = 0L;
        // 基数（万）
        long w_radix = 1L;
        // 基数（亿)
        long y_radix = 1L;
        // 记录万出现的次数
        int w = 0;
        // 记录亿出现的次数
        int y = 0;
        // 记录连续出现单位的次数（数组NUIT中的单位）
        int z = 0;
        for(int i=upper.length()-1; i>=0; i--){
            if(mapD.containsKey(upper.charAt(i)) && upper.charAt(i) != UPPER[0]){
                result = digit * Long.parseLong(String.valueOf(mapD.get(upper.charAt(i)))) + pre;
                pre = result;
                // 重置倍数
                digit = 1L;
                // 重置z
                z = 0;
            } else if(listN.contains(upper.charAt(i))){
                // 形如“壹佰亿”，连续出现单位字符时，需重置倍数
                if((++z) == 2) {
                    digit = 1L;
                }
                if(upper.charAt(i) == NUIT[0]){
                    /* 当数字大于亿小于万亿时，需特殊处理 */
                    digit = (w ==1 && y == 1) ? digit*10L*y_radix : digit*10L*w_radix*y_radix;
                }
                else if(upper.charAt(i) == NUIT[1]){
                    digit = (w ==1 && y == 1) ? digit*100L*y_radix : digit*100L*w_radix*y_radix;
                }
                else if(upper.charAt(i) == NUIT[2]){
                    digit = (w ==1 && y == 1) ? digit*1000L*y_radix : digit*1000L*w_radix*y_radix;
                }
                else if(upper.charAt(i) == NUIT[3]){
                    digit = (w ==1 && y == 1) ? digit*10000L*y_radix : digit*10000L;
                    w_radix = 10000L;
                    ++w;
                }
                else if(upper.charAt(i) == NUIT[4]){
                    digit *= 100000000L;
                    y_radix = 100000000L;
                    ++y;
                }
            }
        }
        return String.valueOf(result);
    }

    /**
     * 把阿拉伯数字转为汉字数字
     * @param digit 待转换数字
     * @return 转换结果
     */
    public static String digitToConvert(Long digit) {
        // 接收最后结果
        StringBuilder result = new StringBuilder();
        // 把数字转换为字符串数组
        String s = String.valueOf(digit);
        char[] chars = s.toCharArray();
        // 获取数字的长度
        int length = s.length();
        // 用来标记当前下标位置，每循环一次加四
        int index = length%4;
        // 记录连续出现0的次数
        int z = 0;

        // 不足完整四位分组的时候，模除结果最大为3，即为千开头
        if (length%4 != 0) {
            for (int i = 0; i <= (length%4)-1; i++) {
                if (mapU.get(chars[i]).equals('零')) {
                    if (++z >= 2) {
                        continue;
                    }
                }
                // 获取对应数字
                result.append(mapU.get(chars[i]));
                if (!mapU.get(chars[i]).equals('零')) {
                    // 获取对应单位
                    result.append(NUIT2[(length%4)-i-1]);
                }
            }
            // 处理完多出来的几位之后添加后缀单位
            result.append(NUIT2[(length/4) + 4]);
        }

        // 有几个四位就有几个分组
        for (int j = (length-(length%4))/4; j > 0 ; j--) {
            // 用来标记单位生成
            int temp = 4;
            // 重置0出现的次数
            z = 0;
            for (int i = index; i < index+4; i++) {
                if (mapU.get(chars[i]).equals('零')) {
                    if (++z >= 2) {
                        temp--;
                        continue;
                    }
                }
                // 获取对应数字
                result.append(mapU.get(chars[i]));
                // 数字不为0的时候才加单位
                if (!mapU.get(chars[i]).equals('零')) {
                    // 获取对应单位
                    result.append(NUIT2[--temp]);
                } else {
                    temp--;
                }
            }
            index += 4;
            // 去除多余的零
            removeZero(result);
            if (index != length) {
                if (z != 4) {
                    // j可以知道现在是第几次循环
                    // 根据循环次数来决定四位组的单位后缀
                    result.append(NUIT2[j+3]);
                }

            }
        }
        return result.toString();
    }

    /**
     * 去除多余的零
     * @param result 字符串
     */
    public static void removeZero(StringBuilder result) {
        // 去除多余的零
        if ("零".equals(result.substring(result.length()-1))) {
            result.deleteCharAt(result.length()-1);
        }
    }

    public static void main(String[] args) {
        System.out.println(convertToDigit("壹拾叁"));
        System.out.println(digitToConvert(300010101000L));
    }
}
